#!/bin/bash

# Elasticsearch 完整自动化安装脚本
set -e

# 配置参数
ES_VERSION="9.1.3"
ES_PORT="9200"
CLUSTER_NAME="centos7-cluster"
NODE_NAME="centos7-node"
mpath="/home/gst/middleware/es"
INSTALL_DIR="$mpath/"
DATA_DIR="$mpath/data"
LOG_DIR="$mpath/logs"
CONFIG_DIR="$mpath/config"
SERVICE_USER="elasticsearch"

# 架构检测
ARCH=$(uname -m)
jtar=""
etar=""
case $ARCH in
    x86_64) 
	    ES_ARCH="x86_64" 
	    ES_URL="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}-linux-x86_64.tar.gz" 
	    jtar="openjdk-17.0.2_linux-x86_x64_bin.tar.gz"
	    etar="elasticsearch-9.1.3-linux-x86_64.tar.gz"
	    ;;
    aarch64|arm64) 
	    ES_ARCH="aarch64"
	    ES_URL="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}-linux-aarch64.tar.gz"
	    jtar="openjdk-17.0.2_linux-aarch64_bin.tar.gz"
	    etar="elasticsearch-9.1.3-linux-aarch64.tar.gz"
	    ;;
    *) 
	    echo "不支持的架构: $ARCH";
	    exit 1 
	    ;;
esac

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# 检查 root 权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本必须以 root 权限运行"
        exit 1
    fi
}

# 安装依赖
install_dependencies() {
    log_info "安装系统依赖..."
    
    yum update -y
    yum install -y wget curl tar gzip jq nmap-ncat
    
    # 安装 Java
    if ! java -version 2>&1 | grep -q "17."; then
        #yum install -y java-17-openjdk-devel
	install_java
        
        # 设置环境变量
        #JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
        #echo "export JAVA_HOME=$JAVA_HOME" >> /etc/profile
        #echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile
        #source /etc/profile
    fi
    
    log_info "Java 版本: $(java -version 2>&1 | head -1)"
}

install_java() {
    log_info "安装 Java 17..."

    # 检查是否已安装 Java 17
    if java -version 2>&1 | grep -q "17."; then
        log_info "Java 17 已安装"
        return 0
    fi


    # 添加 OpenJDK 17 仓库
    yum install -y wget
    #wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz

    # 创建安装目录
    mkdir -p /usr/lib/jvm
    cp -rfv /home/todd/es/$jtar /tmp/
    cd /tmp/
    tar -xzf $jtar -C /usr/lib/jvm

    # 设置 alternatives
    update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-17.0.2/bin/java 1000
    update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk-17.0.2/bin/javac 1000
    update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk-17.0.2/bin/jar 1000

    # 设置环境变量
    #echo "export JAVA_HOME=/usr/lib/jvm/jdk-17.0.2" >> /etc/profile
    #echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile
    source /etc/profile

    log_info "Java 17 安装完成: $(java -version 2>&1 | head -1)"
}


# 创建用户和目录
setup_environment() {
    log_info "创建用户和目录..."
    
    # 创建用户
    if ! id -u $SERVICE_USER >/dev/null 2>&1; then
        useradd -r -s /bin/false -M $SERVICE_USER
    fi
    
    # 创建目录
    mkdir -p $INSTALL_DIR $DATA_DIR $LOG_DIR $CONFIG_DIR
    chown -R $SERVICE_USER:$SERVICE_USER $INSTALL_DIR $DATA_DIR $LOG_DIR $CONFIG_DIR
}

# 下载和安装 Elasticsearch
install_elasticsearch() {
    log_info "下载 Elasticsearch $ES_VERSION ($ES_ARCH)..."
    
    cd /tmp
    #if ! wget --progress=bar:force $ES_URL -O elasticsearch.tar.gz; then
    #    log_error "下载失败，尝试备用镜像..."
    #    ES_URL="https://mirrors.huaweicloud.com/elasticsearch/${ES_VERSION}/elasticsearch-${ES_VERSION}-linux-${ES_ARCH}.tar.gz"
    #    wget --progress=bar:force $ES_URL -O elasticsearch.tar.gz || {
    #        log_error "下载失败"; exit 1
    #    }
    #fi
    cp -rfv /home/todd/es/$etar /tmp/
    log_info "解压安装..."
    tar -xzf $etar -C $INSTALL_DIR --strip-components=1
    chown -R $SERVICE_USER:$SERVICE_USER $INSTALL_DIR
    rm -f $etar
}

# 配置 Elasticsearch
configure_elasticsearch() {
    log_info "配置 Elasticsearch..."
    
    # 创建主配置文件
    cat > $CONFIG_DIR/elasticsearch.yml << EOF
# 集群配置
cluster.name: $CLUSTER_NAME
node.name: $NODE_NAME
node.roles: [ master, data, ingest ]

# 路径配置
path.data: $DATA_DIR
path.logs: $LOG_DIR

# 网络配置
network.host: 0.0.0.0
http.port: $ES_PORT
http.cors.enabled: true
http.cors.allow-origin: "*"

# 发现配置
discovery.type: single-node

# 安全配置
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: false
xpack.security.http.ssl.enabled: false
xpack.license.self_generated.type: trial

# 内存配置
bootstrap.memory_lock: true

# ---------------------------------- Gateway -----------------------------------
#gateway.recover_after_nodes: 1
gateway.recover_after_time: 5m
#gateway.expected_nodes: 1
gateway.expected_data_nodes: 1

#
# ---------------------------------- Logger ------------------------------------
logger.level: INFO
EOF

    # 配置 JVM
    configure_jvm
    
    # 配置系统限制
    configure_system_limits
}

# 配置 JVM
configure_jvm() {
    local mem_gb=$(free -g | awk '/Mem:/ {print $2}')
    local heap_size=$((mem_gb / 2))
    
    # 限制堆大小在 1-31GB 之间
    if [[ $heap_size -lt 1 ]]; then
        heap_size=1
    elif [[ $heap_size -gt 31 ]]; then
        heap_size=31
    fi
    
    mkdir -p $CONFIG_DIR/jvm.options.d
    cat > $CONFIG_DIR/jvm.options.d/heap_size.options << EOF
# JVM 堆内存配置
-Xms${heap_size}g
-Xmx${heap_size}g

# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=150
-XX:G1ReservePercent=25

# 内存优化
-XX:+AlwaysPreTouch
-Xss1m
-XX:MaxDirectMemorySize=536870912
EOF
}

# 配置系统限制
configure_system_limits() {
    cat > /etc/security/limits.d/elasticsearch.conf << EOF
$SERVICE_USER soft nofile 65536
$SERVICE_USER hard nofile 65536
$SERVICE_USER soft memlock unlimited
$SERVICE_USER hard memlock unlimited
$SERVICE_USER soft nproc 4096
$SERVICE_USER hard nproc 4096
EOF

    cat > /etc/sysctl.d/elasticsearch.conf << EOF
vm.max_map_count=262144
fs.file-max=65536
net.core.somaxconn=2048
net.ipv4.tcp_max_syn_backlog=2048
EOF

    sysctl -p /etc/sysctl.d/elasticsearch.conf
}

# 创建系统服务
create_systemd_service() {
    log_info "创建 Systemd 服务..."
    
    cat > /etc/systemd/system/elasticsearch.service << EOF
[Unit]
Description=Elasticsearch
Documentation=https://www.elastic.co
After=network.target

[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_USER
Environment=ES_HOME=$INSTALL_DIR
Environment=ES_PATH_CONF=$CONFIG_DIR
Environment=JAVA_HOME=$JAVA_HOME

WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/bin/elasticsearch

LimitNOFILE=65536
LimitNPROC=4096
LimitMEMLOCK=infinity

TimeoutStopSec=0
KillSignal=SIGTERM
KillMode=process
SendSIGKILL=no
SuccessExitStatus=143

Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable elasticsearch
}

# 等待 Elasticsearch 启动
wait_for_elasticsearch() {
    local max_attempts=60
    local attempt=1
    local wait_seconds=5
    
    log_info "等待 Elasticsearch 启动..."
    
    while [ $attempt -le $max_attempts ]; do
        # 检查进程
        if ! pgrep -f "org.elasticsearch.bootstrap.Elasticsearch" >/dev/null; then
            log_info "尝试 $attempt: 进程未运行"
            sleep $wait_seconds
            attempt=$((attempt + 1))
            continue
        fi
        
        # 检查端口
        if ! ss -tuln | grep -q ":${ES_PORT}"; then
            log_info "尝试 $attempt: 端口未监听"
            sleep $wait_seconds
            attempt=$((attempt + 1))
            continue
        fi
        
        # 测试连接
        local response
        response=$(curl -s -o /dev/null -w "%{http_code}" \
            --connect-timeout 5 \
            --max-time 10 \
            http://localhost:${ES_PORT}/ 2>/dev/null || echo "CURL_ERROR")
        
        if [ "$response" = "200" ] || [ "$response" = "401" ]; then
            log_info "Elasticsearch 启动成功"
            return 0
        fi
        
        log_info "尝试 $attempt: 响应码 $response"
        sleep $wait_seconds
        attempt=$((attempt + 1))
    done
    
    log_error "Elasticsearch 启动超时"
    return 1
}

# 设置密码
setup_passwords() {
    log_info "设置 Elasticsearch 密码..."
    
    # 等待服务完全启动
    sleep 10
    
    # 尝试自动设置密码
    cd $INSTALL_DIR
    if echo "y" | bin/elasticsearch-setup-passwords auto > /tmp/elastic-passwords.txt 2>&1; then
        if [ -f /tmp/elastic-passwords.txt ] && grep -q "PASSWORD elastic" /tmp/elastic-passwords.txt; then
            ELASTIC_PASSWORD=$(grep "PASSWORD elastic" /tmp/elastic-passwords.txt | awk '{print $4}')
            save_credentials "$ELASTIC_PASSWORD"
	    cp /tmp/elastic-passwords.txt $INSTALL_DIR/passwords.txt
            return 0
        fi
    fi
    
    # 如果自动设置失败，尝试交互式
    log_warn "自动设置密码失败，尝试交互式设置..."
    if [ -t 0 ]; then
        bin/elasticsearch-setup-passwords interactive
    else
        # 非交互式环境，尝试使用默认密码
        try_default_passwords
    fi
}

# 保存凭据
save_credentials() {
    local password=$1
    
    # 保存到系统文件
    cat > $INSTALL_DIR/pass << EOF
ELASTIC_USERNAME=elastic
ELASTIC_PASSWORD=$password
ES_HOST=localhost
ES_PORT=$ES_PORT
EOF
    chmod 600 $INSTALL_DIR/pass
    
    # 保存用户可见文件
    cat > /root/elastic-credentials.txt << EOF
================================================
Elasticsearch 安装完成!
访问地址: http://$(hostname -I | awk '{print $1}'):$ES_PORT
用户名: elastic
密码: $password
密码文件: /tmp/elastic-passwords.txt
配置文件: $INATALL_DIR/config/elasticsearch.yml
================================================
EOF
    
    log_info "密码设置完成: elastic:$password"
}

# 尝试默认密码
try_default_passwords() {
    local default_passwords=("changeme" "elastic" "password" "")
    
    for pass in "${default_passwords[@]}"; do
        if curl -s -u "elastic:$pass" http://localhost:${ES_PORT}/ | grep -q "You Know"; then
            log_info "发现默认密码: $pass"
            save_credentials "$pass"
            return 0
        fi
    done
    
    log_error "无法设置密码，请手动执行:"
    log_error "sudo $INSTALL_DIR/bin/elasticsearch-setup-passwords interactive"
    return 1
}

# 配置防火墙
configure_firewall() {
    if command -v firewall-cmd >/dev/null && firewall-cmd --state >/dev/null 2>&1; then
        log_info "配置防火墙..."
        firewall-cmd --permanent --add-port=${ES_PORT}/tcp
        firewall-cmd --reload
    fi
}

# 验证安装
verify_installation() {
    log_info "验证安装..."
    
    # 检查服务状态
    if systemctl is-active --quiet elasticsearch; then
        log_info "✓ Elasticsearch 服务运行正常"
    else
        log_error "✗ Elasticsearch 服务未运行"
        return 1
    fi
    
    # 测试连接
    if source $INSTALL_DIR/pass 2>/dev/null; then
        if curl -s -u "$ELASTIC_USERNAME:$ELASTIC_PASSWORD" http://localhost:${ES_PORT}/ | grep -q "You Know"; then
            log_info "✓ Elasticsearch 连接正常"
            return 0
        fi
    fi
    
    log_error "✗ Elasticsearch 连接测试失败"
    return 1
}

# 主安装函数
main() {
    log_info "开始安装 Elasticsearch $ES_VERSION ($ES_ARCH)"
    
    check_root
    install_dependencies
    setup_environment
    install_elasticsearch
    configure_elasticsearch
    create_systemd_service
    configure_firewall
    
    log_info "启动 Elasticsearch 服务..."
    systemctl start elasticsearch
    
    if wait_for_elasticsearch; then
        setup_passwords
        verify_installation
        log_info "安装完成! 凭据保存在 /root/elastic-credentials.txt"
    else
        log_error "安装过程中出现问题"
        log_info "请检查日志: $LOG_DIR/*.log"
        log_info "尝试手动启动: sudo systemctl status elasticsearch"
    fi
}

# 执行安装
main "$@"
